/**
 * AABillHttpClient.java
 * com.tc.client.AABill.api
 *
 * Function： TODO 
 *
 *   ver     date      		author
 * ──────────────────────────────────
 *   		 2012-7-2 		wangjieming
 *
 * Copyright (c) 2012, TNT All Rights Reserved.
 */

package com.jamin.aabill.http;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import android.text.TextUtils;

import com.jamin.aabill.api.BillException;
import com.jamin.aabill.utils.Configuration;
import com.jamin.aabill.utils.Utils;


/**
 * ClassName:AABillHttpClient
 *
 * @author   wangjieming
 * @version  1.0
 * @since    v1.0
 * @Date	 2012-7-2 上午11:30:27 
 */
public class BillHttpClient {

	private static final String TAG = "BillHttpClient";
	/**
	 * Request Code
	 */
	private static final int OK = 200;// OK: Success!
	private static final int NOT_MODIFIED = 304;// Not Modified: There was no new data to return.
	private static final int BAD_REQUEST = 400;// Bad Request: The request was invalid.  An accompanying error message will explain why. This is the status code will be returned during rate limiting.
	private static final int NOT_AUTHORIZED = 401;// Not Authorized: Authentication credentials were missing or incorrect.
	private static final int FORBIDDEN = 403;// Forbidden: The request is understood, but it has been refused.  An accompanying error message will explain why.
	private static final int NOT_FOUND = 404;// Not Found: The URI requested is invalid or the resource requested, such as a user, does not exists.
	private static final int NOT_ACCEPTABLE = 406;// Not Acceptable: Returned by the Search API when an invalid format is specified in the request.
	private static final int INTERNAL_SERVER_ERROR = 500;// Internal Server Error: Something is broken.  Please post to the group so the AABill team can investigate.
	private static final int BAD_GATEWAY = 502;// Bad Gateway: AABill is down or being upgraded.
	private static final int SERVICE_UNAVAILABLE = 503;// Service Unavailable: The AABill servers are up, but overloaded with requests. Try again later. The search and trend methods use this to indicate when you are being rate limited.

	/**
	 * Http connection params
	 */
	private Map<String, String> requestHeaders = new HashMap<String, String>();
	private static boolean isJDK14orEarlier = false;
	private int connectionTimeout = Configuration.getConnectionTimeout();
	private int readTimeout = Configuration.getReadTimeout();

	public BillHttpClient() {

	}



	public Response post(String url, PostParameter[] postParameters,String session
			) throws BillException {
		String httpMethod = "POST";
		return httpRequest(url, postParameters , httpMethod, session);
	}


	/**
	 * @method httpRequest
	 * @param url
	 * @param postParams
	 * @param httpMethod
	 * @return
	 * @throws BillException
	 * @throws 
	 * @since v1.0
	 */
	public Response httpRequest(String url, PostParameter[] postParams,
			String httpMethod,String session) throws BillException {
		Response res = null;
		HttpURLConnection con = null;
		OutputStream osw = null;
		int responseCode = -1;
		try{
			con = getConnection(url);
			// 设置是否向httpUrlConnection输出，因为这个是post请求，参数要放在 
			// http正文内，因此需要设为true, 默认情况下是false;   
			con.setDoOutput(true);
			// 设置是否从httpUrlConnection读入，默认情况下是true;
			con.setDoInput(true);
			//设定请求的方法为"POST"，默认是GET
			con.setRequestMethod(httpMethod);
			//配置本次连接的Content-type,配置为application/x-www-form-urlencoded的
			con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
			// Post 请求不能使用缓存 
			con.setUseCaches(false);  
			if(!TextUtils.isEmpty(session)){
				con.setRequestProperty("cookie", session); 
			}
			// 连接，从上述第2条中url.openConnection()至此的配置必须要在connect之前完成，
			//要上传的参数
			String postParam = "";
			if (postParams != null) {
				postParam = encodeParameters(postParams);
			}
			Utils.log(TAG,"Request: ");
			Utils.log(TAG,"URL: " + url);
			Utils.log( TAG , "Post Params: " + postParam);
			Utils.log( TAG , "cookie: " + session);
			byte[] bytes = postParam.getBytes("UTF-8");
			con.setRequestProperty("Content-Length" , Integer.toString(bytes.length));
			osw = con.getOutputStream();
			osw.write(bytes);
			//得到响应结果
			res = new Response(con);
			responseCode = con.getResponseCode();

			///////////////////////////////LOG
			Utils.log(TAG,"Response: ");
			Map<String, List<String>> responseHeaders = con.getHeaderFields();
			for (String key : responseHeaders.keySet()) {
				List<String> values = responseHeaders.get(key);
				for (String value : values) {
					if(null != key){
						Utils.log( TAG , key + ": " + value );
					}else{
						Utils.log( TAG ,value );
					}
				}
			}
			///////////////////////////////LOG END
			if (responseCode != OK) {
				throw new BillException(getCause(responseCode) + "\n" + res.asString(), responseCode);
			} 
		} catch (IOException ioe) {
			throw new BillException(ioe.getMessage(), ioe, responseCode);
		}finally{
			try {
				osw.flush();
				osw.close();
			} catch (Exception ignore) {
			}
		}
		return res;
	}

	/* 上传文件至Server的方法 */
	//	public String uploadFile(String actionUrl ,File uploadFile)
	//	{
	////		String end = "\r\n";
	////		String twoHyphens = "--";
	////		String boundary = "*****";
	//		//		try
	//		//		{
	//		URL url = null;
	//		try {
	//			
	//			url = new URL(actionUrl);
	//			HttpURLConnection con = (HttpURLConnection) url.openConnection();
	//			/* 允许Input、Output，不使用Cache */
	//			con.setDoInput(true);
	//			con.setDoOutput(true);
	//			con.setUseCaches(false);
	//			/* 设置传送的method=POST */
	//			con.setRequestMethod("POST");
	//			/* setRequestProperty */
	//			con.setRequestProperty("Connection", "Keep-Alive");
	//			con.setRequestProperty("Charset", "UTF-8");
	//			//配置本次连接的Content-type,配置为application/x-www-form-urlencoded的
	//			con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
	////			con.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
	//			/* 设置DataOutputStream */
	//			DataOutputStream ds = new DataOutputStream(con.getOutputStream());
	////			ds.writeBytes(twoHyphens + boundary + end);
	////			ds.writeBytes("Content-Disposition:form-data; " + "name=\"avatarStream\";filename=\"" + "image.jpg" +"\"" + end);
	////			ds.writeBytes(end);   
	//			/* 取得文件的FileInputStream */
	//			FileInputStream fStream = new FileInputStream(uploadFile);
	//			/* 设置每次写入1024bytes */
	//			int bufferSize = 1024;
	//			byte[] buffer = new byte[bufferSize];
	//
	//			int length = -1;
	//			/* 从文件读取数据至缓冲区 */
	//			while((length = fStream.read(buffer)) != -1)
	//			{
	//				/* 将资料写入DataOutputStream中 */
	//				Utils.log(TAG, "length = " + length);
	//				ds.write(buffer, 0, length);
	//			}
	////			ds.writeBytes(end);
	////			ds.writeBytes(twoHyphens + boundary + twoHyphens + end);
	//			/* close streams */
	//			fStream.close();
	//			ds.flush();
	//			/* 取得Response内容 */
	//			InputStream is = con.getInputStream();
	//			///////////////////////////////LOG
	//			Utils.log(TAG,"Response: ");
	//			Map<String, List<String>> responseHeaders = con.getHeaderFields();
	//			for (String key : responseHeaders.keySet()) {
	//				List<String> values = responseHeaders.get(key);
	//				for (String value : values) {
	//					if(null != key){
	//						Utils.log( TAG , key + ": " + value );
	//					}else{
	//						Utils.log( TAG ,value );
	//					}
	//				}
	//			}
	//			///////////////////////////////LOG END
	//			int ch;
	//			StringBuffer b =new StringBuffer();
	//			while( ( ch = is.read() ) != -1 )
	//			{
	//				b.append( (char)ch );
	//			}
	//			/* 关闭DataOutputStream */
	//			ds.close();
	//			/* 返回结果 */
	//			return b.toString();
	//
	//		} 
	//		catch (MalformedURLException e) {
	//			e.printStackTrace();
	//			return "";
	//		}
	//		catch (IOException e) {
	//			e.printStackTrace();
	//			return "";
	//
	//		}
	//
	//		//		}
	//		//		catch(Exception e){
	//		//			/* 返回失败   */
	//		//			return "";
	//		//		}
	//	}


	public static String encodeParameters(PostParameter[] postParams) {
		StringBuffer buf = new StringBuffer();
		for (int j = 0; j < postParams.length; j++) {
			if (j != 0) {
				buf.append("&");
			}
			try {
				buf.append(URLEncoder.encode(postParams[j].name, "UTF-8"))
				.append("=").append(URLEncoder.encode(postParams[j].value, "UTF-8"));
			} catch (java.io.UnsupportedEncodingException neverHappen) {
			}
		}
		return buf.toString();

	}


	private HttpURLConnection getConnection(String url) throws IOException {
		HttpURLConnection con = null;
		con = (HttpURLConnection) new URL(url).openConnection();
		if (connectionTimeout > 0 && !isJDK14orEarlier) {
			con.setConnectTimeout(connectionTimeout);
		}
		if (readTimeout > 0 && !isJDK14orEarlier) {
			con.setReadTimeout(readTimeout);
		}
		return con;
	}



	private static String getCause(int statusCode){
		String cause = null;
		switch(statusCode){
		case NOT_MODIFIED:
			break;
		case BAD_REQUEST:
			cause = "The request was invalid.  An accompanying error message will explain why. This is the status code will be returned during rate limiting.";
			break;
		case NOT_AUTHORIZED:
			cause = "Authentication credentials were missing or incorrect.";
			break;
		case FORBIDDEN:
			cause = "The request is understood, but it has been refused.  An accompanying error message will explain why.";
			break;
		case NOT_FOUND:
			cause = "The URI requested is invalid or the resource requested, such as a user, does not exists.";
			break;
		case NOT_ACCEPTABLE:
			cause = "Returned by the Search API when an invalid format is specified in the request.";
			break;
		case INTERNAL_SERVER_ERROR:
			cause = "Something is broken.  Please post to the group so the AABill team can investigate.";
			break;
		case BAD_GATEWAY:
			cause = "AABill is down or being upgraded.";
			break;
		case SERVICE_UNAVAILABLE:
			cause = "Service Unavailable: The AABill servers are up, but overloaded with requests. Try again later. The search and trend methods use this to indicate when you are being rate limited.";
			break;
		default:
			cause = "";
		}
		return statusCode + ":" + cause;
	}




}

